# -*- coding: utf-8 -*-
"""
tracer.py - Defines Tracer, Mover, and LineMover objects to handle plot interaction

@author: John Edwardson
"""


class Tracer(object):
    '''Creates an animated crosshairs that allows a curve
       to be traced with the mouse'''

    def __init__(self, canvas, ax, color='grey',
                 ls = '--', lw=1, highlight=True):
        self.canvas = canvas
        self.ax = ax
        self.x = 0
        self.y = 0
        self.vl = self.ax.axvline(0, color=color, ls = ls, lw=lw)
        self.hl = self.ax.axhline(0, color=color, ls = ls, lw=lw)

        self.curve = None
        self.prev = None
        self.text = ['','']
        self.setStatus(False)

    def setCurve(self, curve):
        self.curve = curve

    def setPrev(self, prev):
        self.prev = prev

    def setStatus(self, flag):
        self.vl.set_visible(flag)
        self.hl.set_visible(flag)
        self.status = flag

    def start(self, x, y ):
        #remove any existing crosshairs to create background for blit
        self.setStatus(False)
        self.canvas.draw()
        self.bg = self.canvas.copy_from_bbox(self.ax.bbox)
        #blit the initial crosshairs
        self.setXY(x,y)
        self.setStatus(True)
        self.draw()

    def move(self, x,y, axis="Horizontal"):
        '''Move the tracer along the curve according to
        x,y input.  axis flag determines which axis is controlled'''
        xdata = self.curve.get_xdata(orig=True)
        ydata = self.curve.get_ydata(orig=True)

        #get point on curve closest to (x,y)
        if axis == 'Horizontal':
            idx = (abs(xdata - x)).argmin()
        else:
            idx = (abs(ydata - y)).argmin()

        newx = xdata[idx]
        newy = ydata[idx]
        self.setXY(newx, newy)
        self.draw()

    def draw(self):
        self.canvas.restore_region(self.bg)
        self.ax.draw_artist(self.vl)
        self.ax.draw_artist(self.hl)
        self.canvas.blit(self.ax.bbox)

    def setXY(self, x, y):
        self.vl.set_xdata(x)
        self.hl.set_ydata(y)
        self.text = [str(x), str(y)]

    def stop(self):
        self.highlight(False)
        self.setStatus(False)
        self.hl.remove()
        self.vl.remove()
        self.canvas.draw()

    def setTarget(self, curve, state, x, y, reset=False):
        if reset:
            self.highlight(False)

        self.curve = curve
        self.state = state
        self.highlight(True)
        self.start(x,y)

    def highlight(self, flag, deg=2):
        '''Highlights the targeted curve'''
        if flag:
            self.curve.set_linewidth(self.curve.get_linewidth()+deg)
        else:
            self.curve.set_linewidth(self.curve.get_linewidth()-deg)

class Mover(object):
    '''A simple animation object tied to an event loop to handle dragging
    matplotlib annotations'''

    def __init__(self, canvas, ax, item):
        self.item = item
        self.canvas = canvas
        self.ax = ax

    def start(self):
        #Remove the annotation and copy background for blit

        self.bg = self.canvas.copy_from_bbox(self.ax.bbox)
        #blit initial annotation
        self.item.set_visible(True)
        self.draw()
        self.started = True
        self.canvas.start_event_loop(-1)

    def draw(self):
        self.canvas.restore_region(self.bg)
        self.ax.draw_artist(self.item)
        self.canvas.blit(self.ax.bbox)

    def move(self, x, y):
        self.item.set_position((x,y))
        self.item.xytext = (x,y)
        self.draw()

    def stop(self, x, y, show=False):
        self.started = False
        self.move(x,y)
        self.canvas.stop_event_loop()
        self.item.set_visible(show)
        self.canvas.draw()

class LineMover(Mover):
    '''Extends Mover to animate a draggable line(with one end fixed)'''

    def __init__(self, canvas, axes, item, pos, state, curve):
        Mover.__init__(self, canvas, axes, item)
        self.pos = pos
        self.state = state
        self.curve = curve

    def getData(self):
        return self.state, self.curve

    def move(self, x, y):
        xd = (self.pos[0], x)
        yd = (self.pos[1], y)
        self.item.set_xdata(xd)
        self.item.set_ydata(yd)
        self.draw()


